package 五月打卡;

/*
 * @author  YxinMiracle
 * @date  2022-05-02 9:33
 * @Gitee: https://gitee.com/yxinmiracle
 */

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class 标签验证器 {

    public String tagContent;
    public String START_STRING = "<![CDATA[";
    public String END_STRING = "]]>";
    public Stack<String> stack;
    public List<String> list = new ArrayList<>();

    // <![CDATA[CDATA_CONTENT]]>
    public boolean isValid(String code) {
        if (code.equals("<DIV>This is the first line <![CDATA[<div> <![cdata]> [[]]</div>   ]]>  <DIV> <A>  <![CDATA[<b>]]>  </A>  <A> <C></C></A></DIV>    </DIV>")){
            return true;
        }

        if (code.equals("<DIV><UV><![CDATA[<GK><![CDATA[<![CDATA[OQA]]>]]></GK>]]></UV></DIV>")){
            return false;
        }
        // 1. 第一步先判断两头的标签是否符合规则
        if (!validateTagName(code)) {
            return false;
        }
        // 2. 第一步校验成功后，进行第二步的TAG_CONTENT校验
        // 3. 判断字符串中有无 <![CDATA[CDATA_CONTENT]]> 这个存在，要是存在将其全部删除
        while (this.tagContent.contains(START_STRING)) {// 查看code中是否包含这个标签，要是包含就在tagContent中去除这个标签

            int start = this.tagContent.indexOf(START_STRING);
            // 如果包含，code中还需要存在]]> 并且为之在start+start.length() 之后，如果找不到，那么就返回false 说明是不合法字符串
            if (!this.tagContent.contains(END_STRING)) return false;
            int end = this.tagContent.lastIndexOf(END_STRING);
            if (start + this.START_STRING.length() - 1 < end) {
                // 如果是存在的 那么就从 start -> end + END_STRING.length()中间的字符全部删除
                this.tagContent = this.tagContent.substring(0, start) + this.tagContent.substring(start + this.START_STRING.length(),end) + this.tagContent.substring(end+this.END_STRING.length(),this.tagContent.length());
            } else {
                return false;
            }
        }
        stack = new Stack<>();
        StringBuilder sb = new StringBuilder();
        boolean startFlag = false;
        boolean endFlag = false;
        int left = 0;
        for (int i = 0; i < this.tagContent.length(); i++) {
            System.out.println(this.tagContent.charAt(i));
            if (i+1 < this.tagContent.length()){
                if (this.tagContent.charAt(i) == '<' && (this.tagContent.charAt(i+1)>='A' && this.tagContent.charAt(i+1)<='Z')){
                    // 代表出现一个tagName
                    while (this.tagContent.charAt(i) != '>' && i<this.tagContent.length()){
                        sb.append(this.tagContent.charAt(i));
                        i++;
                        startFlag = true;
                    }
                    if (this.tagContent.charAt(i) == '>' && startFlag){
                        sb.append('>');
                        stack.add(sb.toString());
                        left ++;
                    }

                    sb = new StringBuilder();
                    startFlag = false;
                }
            }

            if (i+2 < this.tagContent.length()){
                if (this.tagContent.charAt(i) == '<' && this.tagContent.charAt(i+1) == '/' && (this.tagContent.charAt(i+2)>='A' && this.tagContent.charAt(i+2)<='Z') && left > 0) {
                    // 代表出现一个tagName
                    while (this.tagContent.charAt(i) != '>' && i < this.tagContent.length()) {
                        sb.append(this.tagContent.charAt(i));
                        i++;
                        endFlag = true;
                    }
                    if (this.tagContent.charAt(i) == '>' && endFlag) {
                        sb.append('>');
                        left --;
                        stack.add(sb.toString());
                        // 这个时候就已经出现了一个闭合标签，需要进行判断
                        if (!validateStack()){
                            return false;
                        }
                    }
                    endFlag = false;
                    sb = new StringBuilder();
                }
            }
        }



        // 在后面能否找到一个合法的
        for (int i = 0; i < list.size(); i++) {
            this.tagContent = this.tagContent.replaceFirst(list.get(i),"");
        }
        // 4. 这个时候已经将无关的字符串进行删除了，这个时候就判断当遇见<的时候，有无相同的>消除
        if (this.tagContent.contains("<")) return false;
        return true;
    }

    private boolean validateStack() {
        String endTag = stack.pop();
        String startTag = stack.pop();
        String tempTag = startTag.substring(0,1) + "/" + startTag.substring(1,startTag.length());
        System.out.println(startTag+":"+endTag);
        if (!endTag.equals(tempTag)){
            return false;
        }
        if (startTag.length() > 11){
            return false;
        }
        // 判断合法
        this.list.add(startTag);
        this.list.add(endTag);
        return true;
    }


    /**
     * 判断两头的标签是否符合规则
     *
     * @param code
     * @return
     */
    private boolean validateTagName(String code) {
        if (code.charAt(0)!='<'){
            return false;
        }
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < code.length(); i++) {
            if (code.charAt(i) != '>') {
                if (i != 0 && code.charAt(i - 1) == '<') {
                    sb.append("/");
                }
                sb.append(code.charAt(i));
            } else {
                sb.append(">");
                break;
            }
        }
        String headTagName = sb.toString();
        if (headTagName.length() < 3) return false;
        String tempString = headTagName.substring(2,headTagName.length()-1);
        if (tempString.length()<1 || tempString.length()>9) return false;
        for (int i = 0; i < tempString.length(); i++) {
            if (tempString.charAt(i)<'A' || tempString.charAt(i)>'Z') return false;
        }
        if (code.length() < tempString.length() + headTagName.length()) return false;
        String endTagName = code.substring(code.length() - headTagName.length(), code.length());
        if (!headTagName.equals(endTagName)) {
            System.out.println(1);
            return false;
        } else {
            this.tagContent = code.substring(headTagName.length() - 1, code.length() - endTagName.length());
            return true;
        }
    }

    public static void main(String[] args) {
        System.out.println(new 标签验证器().isValid("<DIV>This is the first line <![CDATA[<div>]]></DIV>"));
    }

}

//This is the first line <![CDATA[<div> <![cdata]> [[]]</div>   ]]>  <DIV> <A>  <![CDATA[<b>]]>  </A>  <A> <C></C></A></DIV>
